import {WidgetClass, widgetHashKeys} from '@/modules/IDE/widget/atom/widget';
import {WidgetIconButton} from '@/modules/IDE/widget/atom/widgetIconButton';
import {WidgetIconTextButton} from '@/modules/IDE/widget/atom/widgetIconTextButton';
import {WidgetTabBar} from '@/modules/IDE/widget/atom/widgetTabBar';
import {WidgetIcon} from '@/modules/IDE/widget/atom/widgetIcon';
import {WidgetText} from '@/modules/IDE/widget/atom/widgetText';
import {WidgetCode} from '@/modules/IDE/widget/atom/widgetCode';
import {WidgetPoint} from '@/modules/IDE/widget/atom/widgetPoint';
import {WidgetProcessor} from '@/modules/IDE/widget/atom/widgetProcessor';
import {WidgetLevel} from '@/modules/IDE/widget/atom/widgetLevel';
import {WidgetInput} from '@/modules/IDE/widget/atom/widgetInput';
import {WidgetInputNumber} from '@/modules/IDE/widget/atom/widgetInputNumber';
import {WidgetSwitch} from '@/modules/IDE/widget/atom/widgetSwitch';
import {WidgetSlider} from '@/modules/IDE/widget/atom/widgetSlider';
import {WidgetScrollContainer} from '@/modules/IDE/widget/atom/widgetScrollContainer';
import {WidgetSelectInput} from '@/modules/IDE/widget/atom/widgetSelectInput';
import {WidgetDateTime} from '@/modules/IDE/widget/atom/WidgetDateTime';
import {WidgetButtonList} from "@/modules/IDE/widget/atom/widgetButtonList";
import {WidgetListCell} from "@/modules/IDE/widget/atom/widgetListCell";
import {WidgetListView} from "@/modules/IDE/widget/atom/widgetListView";
import {WidgetGridView} from "@/modules/IDE/widget/atom/widgetGridView";
import {WidgetDevice} from "@/modules/IDE/widget/atom/widgetDevice";
import {WidgetDeviceLayout} from "@/modules/IDE/widget/atom/widgetDeviceLayout";
import {WidgetPageView} from "@/modules/IDE/widget/atom/widgetPageView";
import {SpeechRecognition} from '@/modules/IDE/widget/custom/speechRecognition';
import {CameraTracking} from '@/modules/IDE/widget/custom/cameraTracking';
import {MeetingList} from '@/modules/IDE/widget/custom/meetingList';
import {Matrix} from '@/modules/IDE/widget/custom/matrix';
import {Camera} from '@/modules/IDE/widget/custom/camera';
import {CameraView} from '@/modules/IDE/widget/custom/cameraView';
import {UrlPlayer} from '@/modules/IDE/widget/custom/UrlPlayer';
import {WebView} from '@/modules/IDE/widget/custom/webView';
import {PadRelatedRooms} from '@/modules/IDE/widget/custom/padRelatedRooms';
import {DistributeMatrix} from '@/modules/IDE/widget/custom/distributeMatrix';
import {PlatformEZLink} from "@/modules/IDE/widget/custom/platformEZLink";
import {ServiceCall} from "@/modules/IDE/widget/custom/serviceCall";
import {Carousel} from "@/modules/IDE/widget/custom/carousel";
import {MeetingListFunction} from "@/modules/IDE/widget/custom/meetingListFunction";
import {assembleTreeFromArray, deepCopy, generateUID, messageHandle} from '@/utils';
import {UndoRedoHandler} from "@/modules/IDE/undoRedoHandler";
import {SipCall} from "@/modules/IDE/widget/custom/sipCall";

export class WidgetFactory {
  constructor() {
    // 单例模式
    if (typeof WidgetFactory.instance === 'object') {
      return WidgetFactory.instance;
    }
    WidgetFactory.instance = this;
  }

  // 一维数组存储工厂生产的所有 widget，便于查找指定的 widget，空间换时间
  static production = [];
  // 全局撤销/重做处理类实例，挂载到 WidgetFactory 上
  static undoRedoHdl = new UndoRedoHandler();

  static clear() {
    WidgetFactory.production = [];
  }

  // 更新工厂中生产的 widget，并记录初始 hash
  static syncToFactory(widget = {}) {
    WidgetFactory.production.push(widget);
  }

  // 当提交保存后，重置发生更改 widget 的 hash 值，设置为最新的 hash
  static resetWidgetsHash(widgets = []) {
    widgets.forEach(widget => {
      widget.hash = widget.curHash;
    });
  }

  // 根据组件 id 获取组件
  static getWidgetById(id) {
    if (!id) return null;
    return WidgetFactory.production.find((p) => p.id === id);
  }
  // 根据小组件 id 获取组件详情
  static getWidgetByAppendId(id) {
    if (!id) return null;
    return WidgetFactory.production.filter((p) => p.appendageId === id || p.appendDialogId === id);
  }
  // 根据设备/复合组件 id 删除全局弹框
  static getWidgetByDialogId(id) {
    if (!id) return [];
    return WidgetFactory.production.filter((p) => p.appendDialogId === id);
  }
  // 获取组件全路径
  static getWidgetFullPath(widgetId) {
    const widget = WidgetFactory.getWidgetById(widgetId);
    if (!widget) return [];
    const path = [widgetId];
    let parentId = widget.parentId;
    while (parentId) {
      const parent = WidgetFactory.getWidgetById(parentId);
      if (parent) {
        path.push(parentId);
        parentId = parent.parentId;
      } else {
        parentId = '';
      }
    }
    return path.reverse();
  }

  // 获取组件的兄弟组件
  static getWidgetBrothers(widget = {}) {
    const {id, parentId = ''} = widget;
    if (!parentId) return [];
    const parent = WidgetFactory.getWidgetById(parentId);
    if (!parent) return [];
    const {children = []} = parent;
    return children.filter(child => child.id !== id);
  }

  // 为传入的 widget 追加子组件
  // 具体流程图：https://ezprotech.feishu.cn/docx/RcVZdEdTxoUDP9xJekfciUgVnpd
  static widgetAppendChild(parent = {}, child, insertIdx) {
    if (!child) return [];
    const successArr = []; // 记录成功被创建的组件集合
    const getWidgetBelong = (widget = {}) => {
      const {subPageId, relateSubPageId, componentId} = widget;
      if (componentId) return 'component';
      if (subPageId || relateSubPageId) return 'subPage';
      return 'page';
    };
    const judgePageRoot = (widget = {}) => {
      return widget.isRoot;
    };
    const judgeSubPageRoot = (widget = {}) => {
      return widget.type === 'subPage';
    };
    const judgeComponentRoot = (widget = {}) => {
      return ['componentComposite', 'componentDevice', 'compositeWidget'].includes(widget.type);
    };
    const parentBelong = getWidgetBelong(parent);
    const recurseUpdateWidget = (widget = {}) => {
      let canBePasted = true; // 标志是否能进行粘贴
      let ignoreChildren = false; // 标志是否不进行递归子组件
      const childBelong = getWidgetBelong(widget);
      const isPageRoot = judgePageRoot(widget);
      const isSubPageRoot = judgeSubPageRoot(widget);
      const isComponentRoot = judgeComponentRoot(widget);
      switch (parentBelong) {
        case 'page':
          switch (childBelong) {
            case 'page':
              if (isPageRoot) {
                canBePasted = false;
                messageHandle({type: 'warning', msg: `页面根组件不可进行粘贴创建！`});
              } else {
                widget.roomId = parent.roomId;
              }
              break;
            case 'subPage':
              if (widget.roomId === parent.roomId) {
                if (isSubPageRoot) {
                  // 主页与子页进行关联处理
                  const subPageId = widget.relateSubPageId || widget.subPageId;
                  const subPage = WidgetFactory.getWidgetById(subPageId) || {};
                  if (!subPage) {
                    canBePasted = false;
                    messageHandle({type: 'warning', msg: `未查找到关联子页信息，请刷新页面同步房间数据！`});
                  } else {
                    ignoreChildren = true;
                    widget.relateSubPage = true;
                    widget.relateSubPageId = subPageId;
                    widget.isRoot = false;
                    widget.droppable = false;
                    widget.resizable = false;
                    delete widget['subPageId'];
                  }
                } else {
                  delete widget['subPageId'];
                }
              } else {
                if (isSubPageRoot) {
                  // TODO 后续需要支持跨工程拷贝子页面（自动创建子页）
                  canBePasted = false;
                  messageHandle({type: 'warning', msg: `跨工程不可粘贴创建子页面！`});
                } else {
                  widget.roomId = parent.roomId;
                  delete widget['subPageId'];
                }
              }
              break;
            case 'component':
              widget.roomId = parent.roomId;
              delete widget['componentId'];
              widget.draggable = isComponentRoot;
              widget.selectable = isComponentRoot;
              widget.resizable = false;
              widget.droppable = false;
              widget.isLocked = false;
              widget.isRoot = false;
              break;
            default:
              break;
          }
          break;
        case 'subPage':
          switch (childBelong) {
            case 'page':
              if (isPageRoot) {
                canBePasted = false;
                messageHandle({type: 'warning', msg: `页面根组件不可进行粘贴创建！`});
              } else {
                widget.roomId = parent.roomId;
                widget.subPageId = parent.subPageId;
              }
              break;
            case 'subPage':
              if (isSubPageRoot) {
                canBePasted = false;
                messageHandle({type: 'warning', msg: `子页面不可再粘贴创建子页面！`});
              } else {
                widget.roomId = parent.roomId;
                widget.subPageId = parent.subPageId;
              }
              break;
            case 'component':
              widget.roomId = parent.roomId;
              widget.subPageId = parent.subPageId;
              delete widget['componentId'];
              widget.draggable = isComponentRoot;
              widget.selectable = isComponentRoot;
              widget.resizable = false;
              widget.droppable = false;
              widget.isLocked = false;
              widget.isRoot = false;
              break;
            default:
              break;
          }
          break;
        case 'component':
          switch (childBelong) {
            case 'page':
              if (isPageRoot) {
                canBePasted = false;
                messageHandle({type: 'warning', msg: `页面根组件不可进行粘贴创建！`});
              } else {
                if (isComponentRoot) {
                  canBePasted = false;
                  messageHandle({type: 'warning', msg: `自定义组件不可再粘贴创建自定义组件！`});
                } else {
                  widget.componentId = parent.componentId;
                  delete widget['roomId'];
                  // TODO 处理 droppable 状态
                  widget.draggable = true;
                  widget.selectable = true;
                  widget.resizable = true;
                  widget.isLocked = false;
                }
              }
              break;
            case 'subPage':
              widget.componentId = parent.componentId;
              widget.isRoot = false;
              delete widget['roomId'];
              delete widget['subPageId'];
              delete widget['relateSubPage'];
              delete widget['relateSubPageId'];
              break;
            case 'component':
              if (isComponentRoot) {
                canBePasted = false;
                messageHandle({type: 'warning', msg: `自定义组件不可再粘贴创建自定义组件！`});
              } else {
                widget.componentId = parent.componentId;
              }
              break;
            default:
              break;
          }
          break;
        default:
          break;
      }
      if (!canBePasted) return;
      successArr.push(widget);
      if (!ignoreChildren) {
        const {children = []} = widget;
        children.forEach(child => recurseUpdateWidget(child));
      }
    };
    recurseUpdateWidget(child);
    if (!successArr.length) return [];
    // 等待递归处理结束后，再建立父子关联
    child.parentId = parent.id;
    if (insertIdx === undefined) {
      parent.children.push(child);
      child.sortNo = parent.children.length;
    } else {
      parent.children.splice(insertIdx, 0, child);
      child.sortNo = insertIdx + 1;
    }
    return successArr;
  }

  // 为传入的 widget 追加父组件
  static widgetsAppendParent(destParent, widgets = [], groupName = '分组') {
    if (!widgets.length) return;
    // 先根据 sortNo 排序，因为鼠标选择的顺序可能和组件的实际 sortNo 不一致
    widgets.sort((a, b) => a.sortNo - b.sortNo);
    const minTop = Math.min.apply(null, widgets.map(ele => ele.rect.top));
    const minLeft = Math.min.apply(null, widgets.map(ele => ele.rect.left));
    const maxBottom = Math.max.apply(null, widgets.map(ele => ele.rect.top + ele.rect.height));
    const maxRight = Math.max.apply(null, widgets.map(ele => ele.rect.left + ele.rect.width));

    const {roomId, componentId, children = []} = destParent;
    const options = {
      category: 'container',
      name: groupName,
      rect: {
        top: minTop,
        left: minLeft,
        width: maxRight - minLeft,
        height: maxBottom - minTop,
      },
      backStyle: {backgroundColor: 'transparent'},
      roomId,
      componentId,
    }
    const parent = WidgetFactory.generateWidget(options);
    let insertIdx = 0;
    widgets.forEach((widget, index) => {
      const idx = children.findIndex(child => child.id === widget.id);
      // 创建的分组插入数组索引和选中组件中排序第一的保持一致
      index === 0 && (insertIdx = index);
      children.splice(idx, 1);
      const {left, top} = widget.rect;
      widget.rect.top = top - minTop;
      widget.rect.left = left - minLeft;
      WidgetFactory.widgetAppendChild(parent, widget);
    });
    WidgetFactory.widgetAppendChild(destParent, parent, insertIdx);
    return parent;
  }

  // 拷贝组件
  static copyWidget(source = {}, isCloneSubPage = false) {
    const IDMap = {};
    const widgets = [];
    // 先将组件树形结构打平
    WidgetFactory.getWidgetFlattenChildren(source).forEach(widget => {
      const {id: oldId, isDeleted} = widget;
      if (isDeleted) return;
      // 记录新旧组件 id 映射，用于 id 的替换
      const newId = generateUID();
      IDMap[newId] = oldId; // newId => oldId
      widgets.push(widget);
    });
    // 将 widget 列表转化为字符串，再根据 id 映射表进行 id 替换
    let widgetsStr = JSON.stringify(widgets) || '';
    Object.keys(IDMap).forEach(newId => {
      const oldId = IDMap[newId];
      const regExp = new RegExp(oldId, 'g');
      widgetsStr = widgetsStr.replace(regExp, newId);
    });
    // 替换完 id 后对拷贝生成的组件增加 sourceId，记录拷贝来源
    const newWidgets = JSON.parse(widgetsStr) || [];
    newWidgets.forEach(widget => {
      delete widget['_id'];
      widget.sourceId = IDMap[widget.id];
      if (!isCloneSubPage && widget.type === 'subPage') {
        // 如果是拖拽子页面进行的拷贝，则由于子页面的 id 与其 subPageId 相同
        // 会导致上面 id 替换过程中，subPageId 也会被替换，这时需要关联原始的 subPageId
        if (widget.id === widget.subPageId) {
          widget.subPageId = widget.sourceId;
        }
      }
    });
    return WidgetFactory.assembleWidgetFromArray(newWidgets, true);
  }

  // 根据平层 widgets 组件配置数组，生成真实组件实例
  static assembleWidgetFromArray(widgets = [], single = false) {
    const srcData = widgets.map(config => WidgetFactory.generateWidget(config));
    return assembleTreeFromArray({
      srcData: srcData, childKey: 'id', parentKey: 'parentId', single: single
    });
  }

  // 获取组件及其所有子组件平铺数组
  static getWidgetFlattenChildren(widget, optimize = true) {
    const widgets = [];
    const recurseChildren = (widget = {}) => {
      if (optimize) {
        // 清空 children 字段，减少最终网络请求数据大小
        widgets.push({...widget, children: []});
      } else {
        widgets.push(widget);
      }
      const {children = []} = widget;
      children.forEach(child => recurseChildren(child));
    };
    recurseChildren(widget);
    return widgets;
  }

  // 组件比例缩放
  static widgetScaleTransform(widget, sourceRect, targetRect) {
    const {width: sWidth, height: sHeight} = sourceRect;
    const {width: tWidth, height: tHeight} = targetRect;
    const wRatio = (tWidth - sWidth) / sWidth + 1;
    const hRatio = (tHeight - sHeight) / sHeight + 1;
    if (widget.type === 'page') {
      widget.rect.width = targetRect.width;
      widget.rect.height = targetRect.height;
    } else {
      const {width, height, left, top} = widget.rect;
      widget.rect.width = Math.round(width * wRatio);
      widget.rect.height = Math.round(height * hRatio);
      // 对于坐标更改，只对非根层级的组件进行更改
      if (!widget.isRootLevel) {
        widget.rect.left = Math.round(left * wRatio);
        widget.rect.top = Math.round(top * hRatio);
      }
      // 字体、图标、圆角处理
      const sizeRatio = Math.min(wRatio, hRatio);
      // 判断圆角是否为 round 情况
      const judgeRound = (value, size) => {
        return Math.abs(value - size / 2.0) <= 1;
      };
      widget.UI.states.forEach(state => {
        const {backStyle = {}, textStyle, iconStyle} = state;
        // 圆角常规处理
        const {borderRadius = {}} = backStyle;
        const {topLeft, topRight, bottomLeft, bottomRight} = borderRadius;
        borderRadius.topLeft = Math.round(topLeft * sizeRatio);
        borderRadius.topRight = Math.round(topRight * sizeRatio);
        borderRadius.bottomLeft = Math.round(bottomLeft * sizeRatio);
        borderRadius.bottomRight = Math.round(bottomRight * sizeRatio);
        // 圆角 round 处理
        const newBorderRadiusW = Math.round(widget.rect.width / 2.0);
        const newBorderRadiusH = Math.round(widget.rect.height / 2.0);
        if (judgeRound(topLeft, width) && judgeRound(topRight, width)) {
          borderRadius.topLeft = newBorderRadiusW;
          borderRadius.topRight = newBorderRadiusW;
        }
        if (judgeRound(bottomLeft, width) && judgeRound(bottomRight, width)) {
          borderRadius.bottomLeft = newBorderRadiusW;
          borderRadius.bottomRight = newBorderRadiusW;
        }
        if (judgeRound(topLeft, height) && judgeRound(bottomLeft, height)) {
          borderRadius.topLeft = newBorderRadiusH;
          borderRadius.bottomLeft = newBorderRadiusH;
        }
        if (judgeRound(topRight, height) && judgeRound(bottomRight, height)) {
          borderRadius.topRight = newBorderRadiusH;
          borderRadius.bottomRight = newBorderRadiusH;
        }
        if (borderRadius.topLeft === borderRadius.topRight
          && borderRadius.bottomLeft === borderRadius.bottomRight
          && borderRadius.topLeft === borderRadius.bottomLeft) {
          borderRadius.width = borderRadius.topLeft;
        }
        state.backStyle.borderRadius = borderRadius;
        // 字体、图标处理
        textStyle && (state.textStyle.size = Math.round(textStyle.size * sizeRatio));
        iconStyle && (state.iconStyle.size = Math.round(iconStyle.size * sizeRatio));
      });
      // 特殊处理 数值进步器
      if (widget.category === 'inputNumber') {
        const {iconStyle = {}} = widget.UI.data || {};
        const iconSize = iconStyle.size;
        iconSize && (iconStyle.size = Math.round(iconSize * sizeRatio));
      }
      // 特殊处理 视频矩阵
      if (widget.category === 'matrixPage') {
        const {itemSize = {},itemSpace=20,itemVSpace=20,textSize=16} = widget.UI.data || {};
        const width = itemSize.width;
        const height = itemSize.height;
        width && (itemSize.width = Math.round(width * sizeRatio));
        height && (itemSize.height = Math.round(height * sizeRatio));
        itemSpace && (widget.UI.data.itemSpace = Math.round(itemSpace * sizeRatio));
        itemVSpace && (widget.UI.data.itemVSpace = Math.round(itemVSpace * sizeRatio));
        textSize && (widget.UI.data.textSize = Math.round(textSize * sizeRatio));
      }
      // 特殊处理 摄像头
      if (widget.category === 'cameraPage') {
        const {presetSize = {},panelSize=200,textSize=16} = widget.UI.data || {};
        const width = presetSize.width;
        const height = presetSize.height;
        width && (presetSize.width = Math.round(width * sizeRatio));
        height && (presetSize.height = Math.round(height * sizeRatio));
        panelSize && (widget.UI.data.panelSize = Math.round(panelSize * sizeRatio));
        textSize && (widget.UI.data.textSize = Math.round(textSize * sizeRatio));
      }
    }
  }

  // 只过滤出关心变更的必要属性，并进行深拷贝
  static getWidgetNecessaryProperty(srcWidget = {}) {
    const destWidget = {};
    widgetHashKeys.forEach(key => destWidget[key] = srcWidget[key]);
    return deepCopy(destWidget);
  }

  // 获取组件相对于其根组件的坐标
  static getWidgetAbsolutePosition(widget = {}, destPosition) {
    const {parentId, rect} = widget;
    if (!destPosition) {
      const {left = 0, top = 0, width = 0, height = 0} = rect;
      destPosition = {left, top, width, height};
    } else {
      destPosition.left += rect.left;
      destPosition.top += rect.top;
    }
    if (parentId) {
      const parent = WidgetFactory.getWidgetById(parentId);
      parent && WidgetFactory.getWidgetAbsolutePosition(parent, destPosition);
    }
    return destPosition;
  }

  // 获取组件的中点坐标
  static getCenterPosition(parent = {}, rect = {}) {
    const {rect: pRect = {}} = parent;
    const {width: wWidth = 0, height: wHeight = 0} = pRect;
    const {width = 0, height = 0} = rect;
    return {
      top: Math.floor((wHeight - height) / 2),
      left: Math.floor((wWidth - width) / 2)
    };
  }

  // 递归更改组件及其子组件删除状态
  static deleteWidget(widget = {}, deletedWidgets = []) {
    widget.isDeleted = true;
    deletedWidgets.push(widget);
    const {type, subPageId, children = []} = widget;
    if (type === 'subPage' && subPageId) {
      // 同步删除关联了子页的主页内容
      WidgetFactory.production.forEach(p => {
        if (p.relateSubPageId === subPageId) {
          p.isDeleted = true;
          deletedWidgets.push(p);
        }
      });
    }
    children.forEach(child => WidgetFactory.deleteWidget(child, deletedWidgets));
    return deletedWidgets;
  }

  // 更改组件锁定状态
  static updateWidgetLockStatus(widget = {}, isLocked, recurse) {
    widget.isLocked = isLocked;
    if (recurse) {
      const {children = []} = widget;
      children.forEach(child => {
        WidgetFactory.updateWidgetLockStatus(child, isLocked, recurse);
      });
    }
  }

  // 递归更改组件的子组件可选中状态
  static updateChildrenFreezeStatus(widget = {}, freeze) {
    const {children = []} = widget;
    children.forEach(child => {
      child.isFreeze = freeze;
      WidgetFactory.updateChildrenFreezeStatus(child, freeze);
    });
  }

  // 递归更改自定义组件及其子组件可编辑状态
  static updateWidgetEditingStatus(widget = {}, isEditing) {
    const isRoot = ['componentComposite', 'componentDevice','compositeWidget'].includes(widget.type);
    widget.draggable = isRoot || isEditing;
    widget.selectable = isRoot || isEditing;
    widget.resizable = isEditing;
    const {children = []} = widget;
    children.forEach(child => {
      WidgetFactory.updateWidgetEditingStatus(child, isEditing);
    });
  }

  // 重置组件 isHover 状态
  static resetWidgetHoverStatus() {
    WidgetFactory.production.forEach(widget => {
      if (widget.isHover) {
        widget.isHover = false;
      }
    });
  }

  // 刷新传入组件的子组件排序
  static refreshWidgetSortNo(widget = {}) {
    const {children = []} = widget;
    let deletedNum = 0; // 记录被删除的子组件数量
    children.forEach((child, idx) => {
      if (child.isDeleted) {
        deletedNum++;
        return;
      }
      child.sortNo = idx + 1 - deletedNum;
      WidgetFactory.refreshWidgetSortNo(child);
    });
  }

  // 更新新增的组件的 _id
  static refreshWidgetsEntityId(widgets = []) {
    widgets.forEach(IDMap => {
      const {_id, id} = IDMap;
      const widget = WidgetFactory.getWidgetById(id);
      widget._id = _id;
    });
  }

  // 重置 widget 的默认展示 UI
  static resetWidgetDefaultUI() {
    WidgetFactory.production.forEach(widget => {
      // const {origin = '', current = ''} = WidgetFactory.widgetHashMap[widget.id];
      // if (origin !== current) {
      // 重置根组件坐标
      if (widget.isRoot) {
        widget.rect.left = 0;
        widget.rect.top = 0;
      }
      // 重置组件激活的 state
      // widget.UI.state = widget.UI.states[0].id;
      // }
    });
  }

  // 判断两组件的 rect 信息是否一致
  static judgeWidgetRectEqual(rect1 = {}, rect2 = {}) {
    const {left: left1, top: top1, width: width1, height: height1} = rect1;
    const {left: left2, top: top2, width: width2, height: height2} = rect2;
    return left1 === left2 && top1 === top2 && width1 === width2 && height1 === height2;
  }

  // 判断组件是否相互遮挡（超过 4/5 面积）
  static judgeWidgetRectCovered(sourceWidget = {}, targetWidget = {}) {
    // let isTabBar = false;
    const {parentId = ''} = sourceWidget;
    if (parentId) {
      // const parent = WidgetFactory.getWidgetById(parentId);
      // isTabBar = parent && parent.category === 'tabBarPage';
    }
    const {sortNo: sSortNo, rect: sRect} = sourceWidget;
    const {sortNo: tSortNo, rect: tRect} = targetWidget;
    // if (!isTabBar && tSortNo < sSortNo) return false;

    const {left: sLeft, top: sTop, width: sWidth, height: sHeight} = sRect;
    const {left: tLeft, top: tTop, width: tWidth, height: tHeight} = tRect;
    const sArea = sWidth * sHeight;

    const left = Math.max(sLeft, tLeft);
    const right = Math.min(sLeft + sWidth, tLeft + tWidth);
    const top = Math.max(sTop, tTop);
    const bottom = Math.min(sTop + sHeight, tTop + tHeight);
    const width = Math.max(0, right - left);
    const height = Math.max(0, bottom - top);

    return width * height >= sArea * 4 / 5;
  }

  /** 生产函数 **************/
  // 根据组件类型创建 widget 实例
  static generateWidget(options = {}) {
    let widget = undefined;
    switch (options.category) {
      // 原子组件
      case 'container':
        if (options.type === 'subPage') {
          widget = WidgetFactory.createSubPageRelate(options);
        } else {
          widget = WidgetFactory.createContainer(options);
        }
        break;
      case 'text':
        widget = WidgetFactory.createText(options);
        break;
      case 'image':
        widget = WidgetFactory.createImage(options);
        break;
      case 'circleClock':
        widget = WidgetFactory.createClock(options);
        break;
      case 'indicator':
        widget = WidgetFactory.createLoading(options);
        break;
      case 'icon':
        widget = WidgetFactory.createIcon(options);
        break;
      case 'point':
        widget = WidgetFactory.createPoint(options);
        break;
      case 'hDivider':
        widget = WidgetFactory.createDivider(options, 'h');
        break;
      case 'vDivider':
        widget = WidgetFactory.createDivider(options, 'v');
        break;
      case 'iconTextButton':
        widget = WidgetFactory.createIconTextButton(options);
        break;
      case 'iconButton':
        widget = WidgetFactory.createIconButton(options);
        break;
      case 'input':
        widget = WidgetFactory.createInput(options);
        break;
      case 'inputNumber':
        widget = WidgetFactory.createInputNumber(options);
        break;
      case 'switch':
        widget = WidgetFactory.createSwitch(options);
        break;
      case 'processor':
        widget = WidgetFactory.createProcessor(options);
        break;
      case 'level':
        widget = WidgetFactory.createLevel(options);
        break;
      case 'slider':
        widget = WidgetFactory.createSlider(options);
        break;
      case 'selectInput':
        widget = WidgetFactory.createSelectInput(options);
        break;
      case 'dateTime':
        widget = WidgetFactory.createDateTime(options);
        break;
      case 'tabBarPage':
        widget = WidgetFactory.createTabBar(options);
        break;
      case 'scroll':
        widget = WidgetFactory.createScrollContainer(options);
        break;
      case 'listCell':
        widget = WidgetFactory.createListCell(options);
        break;
      case 'listView':
        widget = WidgetFactory.createListView(options);
        break;
      case 'gridView':
        widget = WidgetFactory.createGridView(options);
        break;
      case 'qrCode':
        widget = WidgetFactory.createCode(options);
        break;
      case 'buttonList':
        widget = WidgetFactory.createButtonList(options);
        break;
      case 'dragLayout':
        widget = WidgetFactory.createDeviceWidgetLayout(options);
        break;
      case 'deviceWidget':
        widget = WidgetFactory.createDeviceWidget(options);
        break;
      case 'pageView':
        widget = WidgetFactory.createWidgetPageView(options);
        break;
      // 功能组件
      case 'speechRecognition':
        widget = WidgetFactory.createSpeechRecognition(options);
        break;
      case 'cameraTrack':
        widget = WidgetFactory.createCameraTrack(options);
        break;
      case 'meetingList':
        widget = WidgetFactory.createMeetList(options);
        break;
      case 'matrixPage':
        widget = WidgetFactory.createMatrix(options);
        break;
      case 'cameraPage':
        widget = WidgetFactory.createCamera(options);
        break;
      case 'calendar':
        widget = WidgetFactory.createCalendar(options);
        break;
      case 'urlPlayer':
        widget = WidgetFactory.createUrlPlayer(options);
        break;
      case 'webView':
        widget = WidgetFactory.createWebView(options);
        break;
      case 'distributedMatrix':
        widget = WidgetFactory.createDistributeMatrix(options);
        break;
      case 'cameraView':
        widget = WidgetFactory.createCameraView(options);
        break;
      case 'padRelatedRooms':
        widget = WidgetFactory.createPadRelatedRooms(options);
        break;
      case 'platformEZLink':
        widget = WidgetFactory.createPlatformEZLink(options);
        break;
      case 'imageVideoListPlayer':
        widget = WidgetFactory.createCarousel(options);
        break;
      case 'sipCall':
        widget = WidgetFactory.createSipCall(options);
        break;
      case 'serviceCall':
        widget = WidgetFactory.serviceCall(options);
        break;
      default:
        console.log('##### category #####', options.category);
        break;
    }
    return widget;
  }

  /*======原子组件======*/
  static createPageRoot(baseConfig = {}) {
    const {roomId, window = {}} = baseConfig;
    return new WidgetClass({
      roomId: roomId,
      category: 'container',
      isRoot: true,
      resizable: false,
      backStyle: {backgroundColor: 'bg-color-page'},
      droppable: true,
      rect: {top: 0, left: 0, ...window},
      type: 'page',
      UI: {},
      name: '页面',
    });
  }

  static createSubPageRoot(baseConfig = {}) {
    const {roomId} = baseConfig;
    const subPage = new WidgetClass({
      roomId: roomId,
      category: 'container',
      isRoot: true,
      backStyle: {backgroundColor: 'bg-color-page'},
      droppable: true,
      rect: {top: 0, left: 0, width: 500, height: 500},
      type: 'subPage',
      UI: {},
      name: '子页面',
    });
    subPage.subPageId = subPage.id;
    return subPage;
  }

  static createComponentRoot(baseConfig = {}) {
    const {componentId, category, name, type, widgetSize = {}} = baseConfig;
    switch (category) {
      case 'meetingList':
        const meetingList = new MeetingList({
          componentId: componentId,
          category: 'meetingList',
          isRoot: true,
          resizable: true,
          backStyle: {backgroundColor: 'transparent'},
          droppable: true,
          rect: {top: 0, left: 0, width: 460, height: 480},
          type: type, // componentComposite/componentDevice
          UI: {},
          name: "一键入会"
        });
        meetingList.initTab();
        return meetingList;
      case 'deviceWidget':
        const {rows = 1, columns = 1} = widgetSize;
        const gap = 28;
        return new WidgetDevice({
          componentId: componentId,
          category: 'deviceWidget',
          isRoot: true,
          resizable: false,
          backStyle: {backgroundColor: 'bg-color-page'},
          droppable: true,
          rect: {
            top: 0,
            left: 0,
            width: columns * 180 + (columns - 1) * gap,
            height: rows * 180 + (rows - 1) * gap
          },
          type: type, // componentComposite/componentDevice
          UI: {
            data: {
              widgetSize: widgetSize
            }
          },
          name: name || '小组件',
        });
      default:
        return new WidgetClass({
          componentId: componentId,
          category: 'container',
          isRoot: true,
          resizable: true,
          backStyle: {backgroundColor: 'bg-color-page'},
          droppable: true,
          rect: {top: 0, left: 0, width: 500, height: 500},
          type: type, // componentComposite/componentDevice
          UI: {},
          name: name || '容器',
        });
    }
  }

  static createComponentAppendage(baseConfig = {}) {
    const {componentId, type, name,appendageId,appendDialogId} = baseConfig;
    return new WidgetClass({
      componentId: componentId,
      category: 'container',
      isRoot: true,
      resizable: true,
      backStyle: {backgroundColor: 'bg-color-page'},
      droppable: true,
      rect: {top: 0, left: 0, width: 1024, height: 640},
      type: type, // componentComposite/componentDevice
      UI: {},
      isAppendage: true,
      appendageId:appendageId,
      appendDialogId:appendDialogId,
      name: name || '容器',
    });
  }

  static createSubPageRelate(options = {}) {
    return new WidgetClass({
      category: 'container',
      backStyle: {backgroundColor: 'bg-color-page'},
      droppable: true,
      rect: {top: 0, left: 0, width: 500, height: 500},
      type: 'subPage',
      UI: {},
      name: '子页面',
      ...options
    });
  }

  static createContainer(options = {}) {
    const initSize = {width: 100, height: 100};
    return new WidgetClass({
      category: 'container',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-container'},
      droppable: true,
      type: 'atomic',
      name: '容器',
      ...options
    });
  }

  static createScrollContainer(options = {}) {
    const initSize = {width: 200, height: 200};
    return new WidgetScrollContainer({
      category: 'scroll',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-container'},
      name: "滚动容器",
      type: 'atomic',
      droppable: true,
      ...options
    });
  }

  static createText(options = {}) {
    const initSize = {width: 80, height: 30};
    return new WidgetText({
      category: 'text',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      textStyle: {color: 'text-color-primary', size: 14, weight: 'normal', align: 'center'},
      values: {text: '文本'},
      name: '文本',
      type: 'atomic',
      ...options
    });
  }

  static createImage(options = {}) {
    const initSize = {width: 100, height: 100};
    return new WidgetClass({
      category: 'image',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {
        backgroundImage: '',
        backgroundColor: 'transparent'
      },
      name: '图片',
      type: 'atomic',
      ...options
    });
  }

  static createClock(options = {}) {
    const initSize = {width: 100, height: 100};
    return new WidgetClass({
      category: 'circleClock',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {
        backgroundImage: "",
        backgroundColor: 'transparent'
      },
      name: '时钟',
      type: 'atomic',
      ...options
    });
  }

  static createLoading(options = {}) {
    const initSize = {width: 30, height: 26};
    return new WidgetIcon({
      category: 'indicator',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      iconStyle: {color: 'text-color-primary', size: 24},
      name: 'Loading',
      type: 'atomic',
      ...options
    });
  }

  static createIcon(options = {}) {
    const initSize = {width: 25, height: 25};
    return new WidgetIconButton({
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {
        backgroundColor: 'transparent'
      },
      iconStyle: {color: 'text-color-primary', size: 16},
      values: {icon: "e740"},
      type: 'atomic',
      name: '图标',
      ...options,
      category: 'iconButton',
    });

  }

  static createPoint(options = {}) {
    const initSize = {width: 20, height: 20};
    return new WidgetPoint({
      category: 'point',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'brand-color', borderRadius: {width: 10}},
      type: 'atomic',
      name: '圆点',
      ...options
    });
  }

  static createDivider(options = {}, type = '') {
    const initSize = (type === 'h' ? {width: 40, height: 1} : {width: 1, height: 40});
    return new WidgetClass({
      category: type === 'h' ? 'hDivider' : 'vDivider',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {
        backgroundColor: '#CCCCCC'
      },
      type: 'atomic',
      name: type === 'h' ? '水平分割线' : '垂直分割线',
      ...options
    });
  }

  static createLevel(options = {}) {
    const initSize = {width: 10, height: 200};
    return new WidgetLevel({
      category: 'level',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {
        backgroundColor: 'transparent',
        borderRadius: {
          topLeft: 5,
          topRight: 5,
          bottomLeft: 5,
          bottomRight: 5
        }
      },
      type: 'atomic',
      name: '数值指示器',
      ...options
    });
  }

  static createIconTextButton(options = {}) {
    const initSize = {width: 120, height: 40};
    return new WidgetIconTextButton({
      category: 'iconTextButton',
      backStyle: {backgroundColor: 'bg-color-container', borderRadius: {width: 10}},
      textStyle: {color: 'text-color-primary', size: 14, weight: 'normal', align: 'center'},
      iconStyle: {color: 'text-color-primary', size: 14},
      values: {text: "按钮", icon: ""},
      rect: {top: 0, left: 0, ...initSize},
      type: 'atomic',
      name: '图标文本按钮',
      ...options,
    });
  }

  static createIconButton(options = {}) {
    const initSize = {width: 40, height: 40};
    return new WidgetIconButton({
      category: 'iconButton',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-container', borderRadius: {width: 20}},
      iconStyle: {color: 'text-color-primary', size: 14},
      values: {icon: "e740"},
      type: 'atomic',
      name: '图标按钮',
      ...options
    });
  }

  static createInput(options = {}) {
    const initSize = {width: 150, height: 40};
    return new WidgetInput({
      category: 'input',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {
        border: {width: 1, color: '#F5F5F5'},
        borderRadius: {width: 5},
        backgroundColor: 'bg-color-container'
      },
      textStyle: {color: 'text-color-primary', size: 14, weight: 'normal', align: 'left'},
      type: 'atomic',
      name: '输入框',
      ...options
    });
  }

  static createInputNumber(options = {}) {
    const initSize = {width: 150, height: 40};
    return new WidgetInputNumber({
      category: 'inputNumber',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {
        border: {width: 1, color: '#F5F5F5'},
        borderRadius: {width: 5},
        backgroundColor: 'bg-color-container'
      },
      textStyle: {color: 'text-color-primary', size: 14},
      type: 'atomic',
      name: '数值',
      ...options
    });
  }

  static createSwitch(options = {}) {
    const initSize = {width: 51, height: 30};
    return new WidgetSwitch({
      category: 'switch',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      type: 'atomic',
      name: '开关',
      resizable: false,
      ...options
    });
  }

  static createProcessor(options = {}) {
    const initSize = {width: 200, height: 10};
    return new WidgetProcessor({
      category: 'processor',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {
        backgroundColor: 'transparent',
        borderRadius: {
          topLeft: 5,
          topRight: 5,
          bottomLeft: 5,
          bottomRight: 5
        }
      },
      type: 'atomic',
      name: '进度条',
      ...options
    });
  }

  static createSlider(options = {}) {
    const initSize = {width: 40, height: 200};
    return new WidgetSlider({
      category: 'slider',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      name: "滑条",
      type: 'atomic',
      ...options
    });
  }

  static createSelectInput(options = {}) {
    const initSize = {width: 150, height: 40};
    return new WidgetSelectInput({
      category: 'selectInput',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {border: {width: 1, color: '#F5F5F5'}, borderRadius: {width: 5}, backgroundColor: 'transparent'},
      name: "下拉选择框",
      type: 'atomic',
      ...options
    });
  }

  static createDateTime(options = {}) {
    const initSize = {width: 100, height: 30};
    return new WidgetDateTime({
      category: 'dateTime',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      textStyle: {color: 'text-color-primary', size: 14, weight: 'normal', align: 'center'},
      type: 'atomic',
      name: '日期时间',
      ...options
    });
  }

  static createTabBar(options = {}) {
    const initSize = {width: 600, height: 600};
    return new WidgetTabBar({
      category: 'tabBarPage',
      droppable: false,
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-page'},
      type: 'atomic',
      name: '导航标签页',
      ...options
    });
  }

  static createListCell(options = {}) {
    const initSize = {width: 400, height: 138};
    return new WidgetListCell({
      category: 'listCell',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-container', borderRadius: {width: 8}},
      type: 'atomic',
      droppable: true,
      name: '列表视图item',
      ...options
    });
  }

  static createListView(options = {}) {
    return new WidgetListView({
      category: 'listView',
      resizable: true,
      backStyle: {backgroundColor: 'bg-color-page', border: {width: 1, color: 'component-stroke'}},
      rect: {top: 0, left: 0, width: 450, height: 600},
      name: "列表视图",
      type: 'atomic',
      ...options
    });
  }

  static createGridView(options = {}) {
    return new WidgetGridView({
      category: 'gridView',
      resizable: true,
      backStyle: {backgroundColor: 'bg-color-page', border: {width: 1, color: 'component-stroke'}},
      rect: {top: 0, left: 0, width: 450, height: 450},
      name: "网格视图",
      type: 'atomic',
      ...options
    });
  }

  static createCode(options = {}) {
    const initSize = {width: 100, height: 100};
    return new WidgetCode({
      category: 'qrCode',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      type: 'atomic',
      name: '二维码',
      ...options
    });
  }

  static createButtonList(options = {}) {
    const initSize = {width: 340, height: 50};
    return new WidgetButtonList({
      category: 'buttonList',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      name: '按钮组',
      droppable: false,
      type: "atomic",
      ...options
    });
  }

  static createDeviceWidgetLayout(options = {}) {
    const initSize = {width: 800, height: 500};
    return new WidgetDeviceLayout({
      category: 'dragLayout',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      name: '拖拽布局',
      type: "atomic",
      droppable: false,
      ...options
    });
  }

  static createDeviceWidget(options = {}) {
    const initSize = {width: 115, height: 115};
    return new WidgetDevice({
      category: 'deviceWidget',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {
        backgroundColor: '#EBECF2',
        borderRadius: {
          width: 20,
          topLeft: 20,
          topRight: 20,
          bottomLeft: 20,
          bottomRight: 20,
        },
        shadow: {
          xOffset: 0,
          yOffset: 1,
          blur: 2,
          spread: 0,
          color: "#12131940",
          type: "",
        },
      },
      name: '小组件',
      type: "atomic",
      resizable: false,
      ...options
    });
  }
  static createWidgetPageView(options = {}) {
    const initSize = {width: 1024, height: 768};
    return new WidgetPageView({
      category: 'pageView',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor:  'bg-color-page'},
      name: '滚动页面',
      type: "atomic",
      droppable: false,
      ...options
    });
  }

  /*======功能组件======*/
  static createUrlPlayer(options = {}) {
    const initSize = {width: 300, height: 300};
    return new UrlPlayer({
      category: 'urlPlayer',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      name: '流媒体播放器',
      type: "componentFunction",
      ...options
    });
  }

  static createWebView(options = {}) {
    const initSize = {width: 800, height: 500};
    return new WebView({
      category: 'webView',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-container'},
      name: '网页',
      type: "componentFunction",
      ...options
    });
  }

  static createPlatformEZLink(options = {}) {
    const initSize = {width: 200, height: 200};
    return new PlatformEZLink({
      category: 'platformEZLink',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-container'},
      name: '信息屏组件',
      type: "componentFunction",
      ...options
    });
  }

  static createCarousel(options = {}) {
    const initSize = {width: 600, height: 200};
    return new Carousel({
      category: 'imageVideoListPlayer',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-container'},
      name: '图片轮播',
      type: "componentFunction",
      ...options
    });
  }

  static createDistributeMatrix(options = {}) {
    const initSize = {width: 1000, height: 600};
    return new DistributeMatrix({
      category: 'distributedMatrix',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      name: '分布式矩阵',
      type: "componentFunction",
      ...options
    });
  }

  static createSpeechRecognition(options = {}) {
    const initSize = {width: 80, height: 80};
    return new SpeechRecognition({
      category: 'speechRecognition',
      rect: {top: 0, left: 0, ...initSize},
      style: {
        backgroundImage: 'common/icon_voice.gif',
        backgroundColor: 'transparent'
      },
      ...options
    });
  }

  static createCameraTrack(options = {}) {
    const initSize = {width: 1000, height: 690};
    return new CameraTracking({
      category: 'cameraTrack',
      // resizable: false,
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      style: {backgroundColor: 'bg-color-container'},
      name: '摄像追踪',
      type: "componentFunction",
      ...options
    });
  }

  static createMeetList(options = {}) {
    const initSize = {width: 460, height: 480};
    return new MeetingListFunction({
      category: 'meetingList',
      backStyle: {backgroundColor: 'transparent'},
      rect: {top: 0, left: 0, ...initSize},
      type: 'componentFunction',
      name: "一键入会",
      ...options
    });
  }

  static createMatrix(options = {}) {
    const initSize = {width: 1000, height: 490};
    return new Matrix({
      category: 'matrixPage',
      // resizable: false,
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      name: '视频矩阵',
      type: "componentFunction",
      ...options
    });
  }

  static createCamera(options = {}) {
    const initSize = {width: 1000, height: 450};
    return new Camera({
      category: 'cameraPage',
      // resizable: false,
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      name: '摄像预设',
      type: "componentFunction",
      ...options
    });
  }

  static createCalendar(options = {}) {
    const initSize = {width: 500, height: 600};
    return new WidgetClass({
      category: 'calendar',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {
        backgroundImage: "",
        backgroundColor: 'transparent'
      },
      name: '日历',
      type: 'componentFunction',
      ...options
    });
  }

  static createCameraView(options = {}) {
    const initSize = {width: 400, height: 400};
    return new CameraView({
      category: 'cameraView',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'transparent'},
      name: '摄像头预览组件',
      type: "componentFunction",
      ...options
    });
  }

  static createPadRelatedRooms(options = {}) {
    const initSize = {width: 400, height: 400};
    return new PadRelatedRooms({
      category: 'padRelatedRooms',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-page'},
      name: 'pad关联房间列表',
      type: "componentFunction",
      ...options
    });
  }
  static createSipCall(options = {}) {
    const initSize = {width: 116, height: 46};
    return new SipCall({
      category: 'sipCall',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-container', borderRadius: {width: 5} },
      name: '一键呼叫',
      type: "componentFunction",
      ...options
    });
  }
  static serviceCall(options = {}) {
    const initSize = {width: 800, height: 600};
    return new ServiceCall({
      category: 'serviceCall',
      rect: {top: 0, left: 0, ...initSize},
      backStyle: {backgroundColor: 'bg-color-container', borderRadius: {width: 5} },
      name: '会议服务',
      type: "componentFunction",
      ...options
    });
  }
}
